"""
统一的仓位管理器

支持回测、实盘、模拟盘模式，通过统一接口管理持仓
"""

import logging
from datetime import datetime
from typing import Dict, Optional

logger = logging.getLogger(__name__)


class PositionInfo:
    """持仓信息数据类（集成止损管理）"""
    
    def __init__(self,
                 stock: str,
                 buy_time: datetime,
                 buy_price: float,
                 shares: int,
                 strategy_type: str = 'low',
                 batch: int = 1,
                 stop_loss_config: dict = None):
        """
        初始化持仓信息
        
        Args:
            stock: 股票代码
            buy_time: 买入时间
            buy_price: 买入价格
            shares: 持有股数
            strategy_type: 策略类型（'low'或'high'）
            batch: 当前批次（1或2）
            stop_loss_config: 止损配置（从config.yaml读取）
        """
        self.stock = stock
        self.buy_time = buy_time
        self.buy_price = buy_price
        self.shares = shares
        self.strategy_type = strategy_type
        self.batch = batch
        
        # ===== 止损相关字段 =====
        from config_loader import STOP_LOSS_CONFIG
        config = stop_loss_config or STOP_LOSS_CONFIG
        
        self.stop_loss_enabled = config.get('enabled', True)
        self.stop_loss_strategy = config.get('strategy', 'atr_trailing')
        self.stop_loss_threshold = config.get('threshold', 0.05)  # 固定止损阈值
        self.atr_period = config.get('atr_period', 14)
        self.atr_multiplier = config.get('atr_multiplier', 2.0)
        
        # 止损状态（动态更新）
        self.highest_price = buy_price  # 最高价（用于追踪止损）
        self.current_atr = 0.0          # 当前ATR值
        self.stop_loss_price = 0.0      # 止损线
    
    def initialize_stop_loss(self, stock_data=None):
        """
        初始化止损（买入时调用）
        
        Args:
            stock_data: 股票历史数据（DataFrame），用于计算ATR
        """
        if not self.stop_loss_enabled:
            return
        
        if self.stop_loss_strategy in ('atr', 'atr_trailing'):
            if stock_data is not None and len(stock_data) > 0:
                self.current_atr = self._calculate_atr(stock_data)
                if self.stop_loss_strategy == 'atr':
                    # ATR固定止损：买入价 - K×ATR
                    self.stop_loss_price = self.buy_price - (self.atr_multiplier * self.current_atr)
                else:
                    # ATR追踪止损：初始化最高价和ATR
                    self.highest_price = self.buy_price
                    self.stop_loss_price = self.highest_price - (self.atr_multiplier * self.current_atr)
                
                atr_pct = (self.current_atr / self.buy_price) * 100 if self.buy_price > 0 else 0
                logger.info(f"📊 {self.stock} {self.stop_loss_strategy}止损初始化: "
                           f"买入={self.buy_price:.2f}, ATR={self.current_atr:.2f}({atr_pct:.1f}%), "
                           f"止损线={self.stop_loss_price:.2f}")
            else:
                # 无数据，回退到固定止损
                logger.warning(f"⚠️ {self.stock} 无历史数据，回退到固定{self.stop_loss_threshold:.1%}止损")
                self.stop_loss_strategy = 'fixed'
        
        if self.stop_loss_strategy == 'fixed':
            self.stop_loss_price = self.buy_price * (1 - self.stop_loss_threshold)
    
    def update_stop_loss(self, current_price: float, stock_data=None):
        """
        更新止损状态（每分钟/天调用）
        
        Args:
            current_price: 当前价格
            stock_data: 股票历史数据（用于更新ATR）
        """
        if not self.stop_loss_enabled:
            return
        
        # 更新最高价
        if current_price > self.highest_price:
            self.highest_price = current_price
        
        # ATR追踪止损：动态更新止损线
        if self.stop_loss_strategy == 'atr_trailing':
            if stock_data is not None and len(stock_data) > 0:
                self.current_atr = self._calculate_atr(stock_data)
            
            if self.current_atr > 0:
                # 止损线 = 最高价 - K×ATR
                self.stop_loss_price = self.highest_price - (self.atr_multiplier * self.current_atr)
    
    def should_stop_loss(self, current_price: float, current_date: str) -> tuple:
        """
        检查是否触发止损
        
        Args:
            current_price: 当前价格
            current_date: 当前日期（YYYYMMDD格式）
        
        Returns:
            tuple: (是否止损, 原因说明)
        """
        if not self.stop_loss_enabled:
            return False, ""
        
        # T+1规则检查
        buy_date = self.buy_time.strftime('%Y%m%d') if self.buy_time else ''
        if buy_date == current_date:
            return False, ""  # 当天买入不能当天卖出
        
        if self.stop_loss_strategy == 'fixed':
            # 固定止损
            loss_pct = (self.buy_price - current_price) / self.buy_price
            if loss_pct >= self.stop_loss_threshold:
                return True, f"固定止损 | 浮亏{loss_pct:.2%} ≥ {self.stop_loss_threshold:.2%}"
        
        elif self.stop_loss_strategy in ('atr', 'atr_trailing'):
            # ATR止损
            if current_price <= self.stop_loss_price:
                if self.stop_loss_strategy == 'atr_trailing':
                    profit = ((self.highest_price - self.buy_price) / self.buy_price) * 100
                    drawdown = ((self.highest_price - current_price) / self.highest_price) * 100
                    return True, (f"ATR追踪止损 | "
                                 f"最高{self.highest_price:.2f}(盈利{profit:+.1f}%), "
                                 f"回撤{drawdown:.1f}%, "
                                 f"跌破止损线{self.stop_loss_price:.2f}")
                else:
                    actual_loss = (self.buy_price - current_price) / self.buy_price
                    return True, f"ATR止损 | 跌破止损线{self.stop_loss_price:.2f}, 实际亏损{actual_loss:.2%}"
        
        return False, ""
    
    def _calculate_atr(self, stock_data) -> float:
        """
        计算ATR（Average True Range）
        
        Args:
            stock_data: DataFrame，包含 high, low, close 列
        
        Returns:
            float: ATR值
        """
        try:
            import pandas as pd
            import numpy as np
            
            if len(stock_data) < 2:
                return 0.0
            
            high = stock_data['high']
            low = stock_data['low']
            close = stock_data['close'].shift(1)
            
            # TR = max(high-low, abs(high-close_prev), abs(low-close_prev))
            tr1 = high - low
            tr2 = abs(high - close)
            tr3 = abs(low - close)
            
            tr = pd.concat([tr1, tr2, tr3], axis=1).max(axis=1)
            
            # 计算ATR（使用SMA）
            period = min(self.atr_period, len(tr))
            atr = tr.rolling(window=period).mean()
            
            return float(atr.iloc[-1]) if not pd.isna(atr.iloc[-1]) else 0.0
            
        except Exception as e:
            logger.error(f"计算ATR时出错: {e}")
            return 0.0
    
    def to_dict(self) -> dict:
        """转换为字典"""
        return {
            'stock': self.stock,
            'buy_time': self.buy_time,
            'buy_price': self.buy_price,
            'shares': self.shares,
            'strategy_type': self.strategy_type,
            'batch': self.batch,
            'stop_loss_enabled': self.stop_loss_enabled,
            'stop_loss_strategy': self.stop_loss_strategy,
            'highest_price': self.highest_price,
            'stop_loss_price': self.stop_loss_price
        }
    
    def __repr__(self):
        return (f"PositionInfo({self.stock}, price={self.buy_price:.2f}, "
                f"shares={self.shares}, type={self.strategy_type}, "
                f"stop_loss={self.stop_loss_strategy})")


class PositionManager:
    """
    统一的仓位管理器
    
    适用于回测、实盘、模拟盘所有模式
    """
    
    def __init__(self, mode: str = 'backtest', trader=None):
        """
        初始化仓位管理器
        
        Args:
            mode: 运行模式
                - 'backtest': 回测模式（使用内存模拟）
                - 'live': 实盘模式
                - 'simulation': 模拟盘模式
            trader: 交易接口（实盘/模拟盘需要，用于同步真实持仓）
        """
        self.mode = mode
        self.trader = trader
        
        # 统一的持仓存储
        self.positions: Dict[str, PositionInfo] = {}
        
        # 条件A触发次数（用于分批减仓）
        self.condition_a_count: Dict[str, int] = {}
        
        logger.info(f"初始化仓位管理器: mode={mode}, trader={'已配置' if trader else '未配置'}")
        
        # 如果是实盘/模拟盘，同步真实持仓
        if mode in ('live', 'simulation') and trader:
            self.sync_positions_from_trader()
    
    def sync_positions_from_trader(self):
        """
        从交易接口同步真实持仓到管理器
        （仅用于实盘/模拟盘模式）
        """
        if not self.trader:
            logger.warning("交易接口未配置，无法同步持仓")
            return
        
        try:
            from datetime import timedelta
            
            real_positions = self.trader.query_stock_positions()
            
            # QMT返回的是列表，不是字典
            if isinstance(real_positions, list):
                for pos in real_positions:
                    stock = pos.stock_code if hasattr(pos, 'stock_code') else str(pos)
                    
                    # 尝试获取真实买入日期（QMT持仓对象的open_date字段）
                    buy_time = None
                    if hasattr(pos, 'open_date') and pos.open_date:
                        try:
                            # open_date格式可能是 '20250224' 或 '2025-02-24'
                            date_str = str(pos.open_date).replace('-', '')[:8]
                            buy_time = datetime.strptime(date_str, '%Y%m%d')
                            logger.debug(f"{stock} 从QMT获取买入日期: {buy_time.date()}")
                        except Exception as e:
                            logger.warning(f"{stock} 解析开仓日期失败: {pos.open_date}, 错误: {e}")
                    
                    # 如果无法获取买入日期，假设是历史持仓（很久以前买的）
                    if buy_time is None:
                        buy_time = datetime.now() - timedelta(days=365)
                        logger.warning(f"{stock} 无法获取开仓日期，假设为历史持仓（1年前）")
                    
                    # 创建持仓信息
                    position_info = PositionInfo(
                        stock=stock,
                        buy_time=buy_time,  # 真实买入时间
                        buy_price=getattr(pos, 'avg_price', 0.0),
                        shares=getattr(pos, 'volume', 0),
                        strategy_type='low',  # 默认值，需要从缓存恢复
                        batch=1  # 默认值
                    )
                    self.positions[stock] = position_info
            else:
                # 兼容旧的字典格式
                for stock, pos_data in real_positions.items():
                    buy_time = datetime.now() - timedelta(days=365)
                    logger.warning(f"{stock} 使用字典格式持仓，假设为历史持仓")
                    
                    position_info = PositionInfo(
                        stock=stock,
                        buy_time=buy_time,
                        buy_price=pos_data.get('avg_price', 0.0),
                        shares=pos_data.get('volume', 0),
                        strategy_type='low',
                        batch=1
                    )
                    self.positions[stock] = position_info
            
            logger.info(f"从交易接口同步了 {len(real_positions)} 个持仓")
            
        except Exception as e:
            logger.error(f"同步持仓失败: {str(e)}")
    
    def get_position(self, stock: str) -> Optional[PositionInfo]:
        """
        获取持仓信息
        
        Args:
            stock: 股票代码
            
        Returns:
            PositionInfo: 持仓信息，如果没有持仓则返回None
        """
        return self.positions.get(stock)
    
    def has_position(self, stock: str) -> bool:
        """
        判断是否持有某只股票
        
        Args:
            stock: 股票代码
            
        Returns:
            bool: 是否持有
        """
        return stock in self.positions
    
    def add_position(self, stock: str, position_info: PositionInfo):
        """
        添加或更新持仓
        
        Args:
            stock: 股票代码
            position_info: 持仓信息
        """
        self.positions[stock] = position_info
        logger.debug(f"添加持仓: {stock}, {position_info.shares}股 @ {position_info.buy_price:.2f}")
    
    def remove_position(self, stock: str):
        """
        移除持仓
        
        Args:
            stock: 股票代码
        """
        if stock in self.positions:
            position = self.positions[stock]
            del self.positions[stock]
            logger.debug(f"移除持仓: {stock}, 原持仓{position.shares}股")
        
        # 同时清除条件A计数
        if stock in self.condition_a_count:
            del self.condition_a_count[stock]
    
    def update_shares(self, stock: str, new_shares: int):
        """
        更新持仓股数（用于部分平仓）
        
        Args:
            stock: 股票代码
            new_shares: 新的股数
        """
        if stock in self.positions:
            old_shares = self.positions[stock].shares
            self.positions[stock].shares = new_shares
            logger.debug(f"更新持仓: {stock}, {old_shares}股 -> {new_shares}股")
            
            # 如果股数为0，则移除持仓
            if new_shares <= 0:
                self.remove_position(stock)
    
    def get_all_positions(self) -> Dict[str, PositionInfo]:
        """
        获取所有持仓
        
        Returns:
            Dict[str, PositionInfo]: 所有持仓信息
        """
        return self.positions.copy()
    
    def get_condition_a_count(self, stock: str) -> int:
        """
        获取条件A触发次数
        
        Args:
            stock: 股票代码
            
        Returns:
            int: 触发次数
        """
        return self.condition_a_count.get(stock, 0)
    
    def increment_condition_a_count(self, stock: str) -> int:
        """
        增加条件A触发次数
        
        Args:
            stock: 股票代码
            
        Returns:
            int: 新的触发次数
        """
        if stock not in self.condition_a_count:
            self.condition_a_count[stock] = 0
        
        self.condition_a_count[stock] += 1
        return self.condition_a_count[stock]
    
    def reset_condition_a_count(self, stock: str):
        """
        重置条件A触发次数
        
        Args:
            stock: 股票代码
        """
        if stock in self.condition_a_count:
            del self.condition_a_count[stock]
    
    def calculate_profit_loss(self, stock: str, current_price: float) -> tuple:
        """
        计算盈亏
        
        Args:
            stock: 股票代码
            current_price: 当前价格
            
        Returns:
            tuple: (盈亏金额, 盈亏比例)
        """
        position = self.get_position(stock)
        if not position:
            return 0.0, 0.0
        
        profit_loss = (current_price - position.buy_price) * position.shares
        profit_loss_pct = (current_price - position.buy_price) / position.buy_price
        
        return profit_loss, profit_loss_pct
    
    def reset(self):
        """
        重置所有持仓（仅用于回测模式）
        """
        if self.mode != 'backtest':
            logger.warning(f"{self.mode}模式下不应该调用reset()方法")
            return
        
        self.positions.clear()
        self.condition_a_count.clear()
        logger.info("重置所有持仓")
    
    def get_summary(self) -> dict:
        """
        获取持仓摘要
        
        Returns:
            dict: 摘要信息
        """
        summary = {
            'mode': self.mode,
            'total_positions': len(self.positions),
            'positions': {}
        }
        
        for stock, pos in self.positions.items():
            summary['positions'][stock] = {
                'buy_price': pos.buy_price,
                'shares': pos.shares,
                'strategy_type': pos.strategy_type,
                'batch': pos.batch,
                'buy_time': pos.buy_time.strftime('%Y-%m-%d %H:%M:%S') if pos.buy_time else None,
                'stop_loss_price': pos.stop_loss_price,
                'highest_price': pos.highest_price
            }
        
        return summary
    
    # ===== 止损管理方法（集成在PositionManager中）=====
    
    def initialize_stop_loss(self, stock: str, stock_data=None):
        """
        初始化止损（买入时调用）
        
        Args:
            stock: 股票代码
            stock_data: 股票历史数据（用于计算ATR）
        """
        position = self.get_position(stock)
        if position:
            position.initialize_stop_loss(stock_data)
    
    def update_stop_loss(self, stock: str, current_price: float, stock_data=None):
        """
        更新止损状态（每分钟/天调用）
        
        Args:
            stock: 股票代码
            current_price: 当前价格
            stock_data: 股票历史数据（用于更新ATR）
        """
        position = self.get_position(stock)
        if position:
            position.update_stop_loss(current_price, stock_data)
    
    def check_stop_loss(self, stock: str, current_price: float, current_date: str) -> tuple:
        """
        检查是否触发止损
        
        Args:
            stock: 股票代码
            current_price: 当前价格
            current_date: 当前日期（YYYYMMDD格式）
        
        Returns:
            tuple: (是否止损, 原因说明)
        """
        position = self.get_position(stock)
        if position:
            return position.should_stop_loss(current_price, current_date)
        return False, ""
    
    def update_all_stop_loss(self, price_dict: dict, stock_data_dict: dict = None):
        """
        批量更新所有持仓的止损状态
        
        Args:
            price_dict: 价格字典 {stock: current_price}
            stock_data_dict: 股票数据字典 {stock: DataFrame}
        """
        for stock, position in self.positions.items():
            if stock in price_dict:
                current_price = price_dict[stock]
                stock_data = stock_data_dict.get(stock) if stock_data_dict else None
                position.update_stop_loss(current_price, stock_data)
    
    def check_all_stop_loss(self, price_dict: dict, current_date: str) -> dict:
        """
        批量检查所有持仓的止损情况
        
        Args:
            price_dict: 价格字典 {stock: current_price}
            current_date: 当前日期（YYYYMMDD格式）
        
        Returns:
            dict: 需要止损的股票及原因 {stock: reason}
        """
        stop_loss_list = {}
        for stock, position in self.positions.items():
            if stock in price_dict:
                should_stop, reason = position.should_stop_loss(price_dict[stock], current_date)
                if should_stop:
                    stop_loss_list[stock] = reason
        return stop_loss_list
    
    def __repr__(self):
        return f"PositionManager(mode={self.mode}, positions={len(self.positions)})"
